package com.csx.springcloud.invoke.resttemplate.controller;

import com.alibaba.fastjson.JSON;
import com.csx.springcloud.invoke.resttemplate.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.net.URI;
import java.util.HashMap;
import java.util.Map;

/**
 * @author cuisongxu
 * @date 2023/3/11 13:47
 */
@RequestMapping("/resttemplate")
@RestController
public class RestTemplateInvokeController {

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 1. GET 请求
     *  - GetForObject 和 GetForEntity 的区别在于:
     *   <p>GetForObject 直接返回Body; </p>
     *   <p>GetForEntity 返回完整响应,包括 Body,Header等</p>
     *
     */
    @GetMapping("/get")
    public String restTemplateGet() {

        // 使用方式一: 参数拼接在URL中
        String url = "http://localhost:8001/restTarget/get?username=zhangsan";
        String res = restTemplate.getForObject(url, String.class);
        ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
        System.out.println("参数拼接在URL中 的返回结果: " + res);
        System.out.println("参数拼接在URL中 的返回结果(完整): " + response);


        // 使用方式二: 传参替换
        url = "http://localhost:8001/restTarget/get?username={?}";
        res = restTemplate.getForObject(url, String.class, "zhangsan");
        response = restTemplate.getForEntity(url, String.class, "zhangsan");
        System.out.println("传参替换 的返回结果: " + res);
        System.out.println("传参替换 的返回结果(完整): " + response);


        // 使用方式三: map传参
        url = "http://localhost:8001/restTarget/get?username={username}";
        Map<String, Object> params = new HashMap<>();
        params.put("username", "zhangsan");
        res = restTemplate.getForObject(url, String.class, params);
        response = restTemplate.getForEntity(url, String.class, params);
        System.out.println("map传参 的返回结果: " + res);
        System.out.println("map传参 的返回结果(完整): " + response);


        // 使用方式四: URI访问
        URI uri = URI.create("http://localhost:8001/restTarget/get?username=zhangsan");
        res = restTemplate.getForObject(uri, String.class);
        response = restTemplate.getForEntity(uri, String.class);
        System.out.println("URI访问 的 返回结果: " + res);
        System.out.println("URI访问 的 返回结果(完整): " + response);


        // 使用方式五: 添加请求头
        url = "http://localhost:8001/restTarget/get?username=zhangsan";
        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.add("token", "123");
        response = restTemplate.exchange(url, HttpMethod.GET,new HttpEntity<String>(headers),String.class, params);
        System.out.println("添加请求头 的 返回结果(完整): " + response);

        return "restTemplate GET test";
    }


    /**
     * 2. 发送 post 请求
     * <p>参数1: 必填,请求地址的URL</p>
     * <p>参数2: 必填,请求体,通过LinkedMultiValueMap对象封装</p>
     * <p>参数3: 必填,响应数据类型</p>
     */
    @PostMapping("/post")
    public String restTemplatePost() {

        // 案例一: ContentType = multipart/form-data,此时被调用接口不使用 @RequestBody
        // 构造请求体
        LinkedMultiValueMap<String, Object> requestBody = new LinkedMultiValueMap<>();
        requestBody.set("name", "zhangsan");
        requestBody.set("age", 18);
        requestBody.set("city.cityName", "shenzhen");
        requestBody.set("city.position", "zg");
        requestBody.set("param", "param");
        String url = "http://localhost:8001/restTarget/post";
        // 构造请求头
        HttpHeaders headers = new HttpHeaders();
        // 设置自定义header头
        headers.set("mock_header", "mock_header_value");
        HttpEntity<LinkedMultiValueMap<String, Object>> httpRequestEntity = new HttpEntity<>(requestBody, headers);
        String res = restTemplate.postForObject(url, httpRequestEntity, String.class);
        ResponseEntity<String> response = restTemplate.postForEntity(url, httpRequestEntity, String.class);
        System.out.println("使用方式一 返回结果: " + res);
        System.out.println("使用方式一 返回结果(完整): " + response);



        // 案例二: ContentType = application/json,此时被调接口使用 @RequestBody
        url = "http://localhost:8001/restTarget/post2?param=paramValue";
        // 构造请求头
        headers = new HttpHeaders();
        // 设置内容类型。默认为 multipart/form-data,此时如果被调接口使用 @RequestBody 接收就会报错
        headers.setContentType(MediaType.APPLICATION_JSON);
        // 设置自定义header头
        headers.set("mock_header", "mock_header_value");
        // 构造请求体
        User user = new User("zhangsan", 18, new User.City("shenzhen", "zg"));
        String requestBodyStr = JSON.toJSONString(user);
        RequestEntity<String> requestEntity = new RequestEntity<>(requestBodyStr, headers, HttpMethod.POST, URI.create(url));
        response = restTemplate.exchange(requestEntity, String.class);
        System.out.println("使用方式二 返回结果(完整): " + response);


        // 案例三: postForLocation 返回新创建资源的URL
        url = "http://localhost:8001/restTarget/postLocation";
        MultiValueMap<String, Object> requestParams = new LinkedMultiValueMap<>();
        requestParams.add("param1", "张三");
        requestParams.add("param2", "code");
        URI uri = restTemplate.postForLocation(url, requestParams);
        System.out.println("案例三 返回结果: " + uri);


        return "restTemplate POST test";
    }


    /**
     * 3. 发送 put 请求
     */
    @PutMapping("/put")
    public String restTemplatePut() {

        return "xxx";
    }




    /**
     * 4. 发送 delete 请求
     */

    @GetMapping("/testError")
    public String testError() {
        ResponseEntity<String> res = restTemplate.getForEntity("http://localhost:8001/resttemplate/error", String.class);
        return res.getBody();
    }

    @GetMapping("/error")
    public String error() {
        throw new RuntimeException("Error!");
    }
}
